﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HeresyManager
{
    [Serializable]
    public abstract class Rank
    {
        public abstract int MinimumExp { get; }
        public abstract String Name { get; }

        public virtual bool IsPreconditionSatisfied(Character c)
        {
            return c.SpendExp >= MinimumExp;
        }

        public abstract Buyable[] Buyables { get; }

        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
                return false;
            return true;
        }

        public override int GetHashCode()
        {
            return this.GetType().GetHashCode();
        }

        public override string ToString()
        {
            return Name;
        }

        [Serializable]
        public abstract class Buyable : IPrecondition
        {


            public abstract int Cost
            {
                get;
            }
            public abstract String Name
            {
                get;
            }

            public virtual IEnumerator<Comunication.Comunicator> Accire(Character c)
            {
                c.SpendExp += Cost;
                if (false) yield return null;
            }
            public virtual bool DeAccire(Character c)
            {
                c.SpendExp -= Cost;
                return true;
            }


            public virtual bool IsPreconditionSattisfied(Character c)
            {

                return c.AvailableExp >= Cost;
            }


            public override string ToString()
            {
                return Name;
            }


        }
        [Serializable]
        internal class SkillBuyable : Buyable
        {
            private Skill s;
            private int cost;
            public SkillBuyable(Skill s, int cost = 100)
            {
                this.s = s;
                this.cost = cost;
            }

            public override int Cost
            {
                get { return cost; }
            }

            public override string Name
            {
                get { return s.ToString(); }
            }

            public override IEnumerator<Comunication.Comunicator> Accire(Character c)
            {
                var e = c.AddSkill(s, this);
                while (e.MoveNext())
                    yield return e.Current;
                e = base.Accire(c);
                while (e.MoveNext())
                    yield return e.Current;
            }

            public override bool DeAccire(Character c)
            {
                return base.DeAccire(c) & c.RemoveSkill(s, this);
            }

            public override bool IsPreconditionSattisfied(Character c)
            {
                return base.IsPreconditionSattisfied(c) && s.IsPreconditionSattisfied(c) && c.Skills.All(tup => !Object.ReferenceEquals(this, tup.Item2));
            }
        }
        [Serializable]
        internal class TalentBuyable : Buyable
        {
            private Talent t;
            private int cost;
            public TalentBuyable(Talent t, int cost = 100)
            {
                this.t = t;
                this.cost = cost;
            }

            public override int Cost
            {
                get { return cost; }
            }

            public override string Name
            {
                get { return t.ToString(); }
            }

            public override IEnumerator<Comunication.Comunicator> Accire(Character c)
            {
                var e = c.AddTalent(t, this);
                while (e.MoveNext())
                    yield return e.Current;
                e = base.Accire(c);
                while (e.MoveNext())
                    yield return e.Current;
            }

            public override bool DeAccire(Character c)
            {
                return base.DeAccire(c) & c.RemoveTalent(t, this);
            }

            public override bool IsPreconditionSattisfied(Character c)
            {
                return base.IsPreconditionSattisfied(c) && t.IsPreconditionSattisfied(c) && c.Talents.All(tup => !Object.ReferenceEquals(this, tup.Item2));
            }
        }

        [Serializable]
        internal class TraitBuyable : Buyable
        {
            private Trait t;
            private int cost;
            public TraitBuyable(Trait t, int cost = 100)
            {
                this.t = t;
                this.cost = cost;
            }

            public override int Cost
            {
                get { return cost; }
            }

            public override string Name
            {
                get { return t.ToString(); }
            }

            public override IEnumerator<Comunication.Comunicator> Accire(Character c)
            {
                var e = c.AddTrait(t, this);
                while (e.MoveNext())
                    yield return e.Current;
                e = base.Accire(c);
                while (e.MoveNext())
                    yield return e.Current;
            }

            public override bool DeAccire(Character c)
            {
                return base.DeAccire(c) & c.RemoveTrait(t, this);
            }

            public override bool IsPreconditionSattisfied(Character c)
            {
                return base.IsPreconditionSattisfied(c) && c.Traits.All(tup => !Object.ReferenceEquals(this, tup.Item2));
            }
        }

    }
}
